package com.daydayup.learn;


import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 父子线程之间传递ThreadLocal数据
 */
@Slf4j
@ControllerAdvice
public class ThreadLocalDemoV4 {

    public static void main(String[] args) throws InterruptedException {
        m2();
    }

    /**
     * 通过引用阿里的包实现子线程能获取到父线程的ThreadLocal变更后的数据
     */
    static void m2() {
        TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();
        // 为了看到效果,这里创建大小为1的线程池方便看
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        // 这里需要用TtlExecutors.getTtlExecutorService将原线程池包装下
        threadPool = TtlExecutors.getTtlExecutorService(threadPool);
        // 这里是主线程,使用transmittableThreadLocal.set放入值
        transmittableThreadLocal.set(Thread.currentThread().getName()+"-Java");
        log.info("major:{}", transmittableThreadLocal.get());
        threadPool.execute(() -> {
            log.info("threadLocal第一次获取major:{}", transmittableThreadLocal.get());
        });

        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); }
        System.out.println();
        System.out.println();
        transmittableThreadLocal.set(Thread.currentThread().getName()+"-Vue,我已经修改了");
        log.info("major:{}", transmittableThreadLocal.get());
        threadPool.execute(() -> {
            log.info("threadLocal第二次获取major:{}", transmittableThreadLocal.get());
        });
        threadPool.shutdown();
    }

    /**
     * InheritableThreadLocal可以访问父线程的ThreadLocal数据，但是当父线程的本地变量被修改时，无法获取变更后的值
     */
    static void m1() {
        InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();
        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        threadLocal.set(Thread.currentThread().getName()+"PHP");
        inheritableThreadLocal.set(Thread.currentThread().getName()+"Java");

        log.info("1 threadLocal:{}", threadLocal.get());
        log.info("1 major:{}", inheritableThreadLocal.get());

        new Thread(() -> {
            log.info("threadLocal:{}", threadLocal.get());
            log.info("major:{}",inheritableThreadLocal.get());
        },"thread1").start();

        new Thread(() -> {
            log.info("threadLocal:{}", threadLocal.get());
            log.info("major:{}",inheritableThreadLocal.get());
        },"thread2").start();

        new Thread(() -> {
            log.info("threadLocal:{}", threadLocal.get());
            log.info("major:{}",inheritableThreadLocal.get());
        },"thread3").start();
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        // 首次获取父线程的本地变量
        threadPool.submit(() -> {
            log.info("threadLocal:{}", threadLocal.get());
            log.info("major:{}",inheritableThreadLocal.get());
        });
        // 修改父线程的本地变量值
        inheritableThreadLocal.set(Thread.currentThread().getName()+" Go");
        // 第二次获取父线程的本地变量
        threadPool.submit(() -> {
            log.info("threadLocal:{}", threadLocal.get());
            log.info("major:{}",inheritableThreadLocal.get());
        });

        log.info("2 threadLocal:{}", threadLocal.get());
        log.info("2 major:{}", inheritableThreadLocal.get());
    }
}
